#include "LOGR_user_manager.h"

short
LOGR_is_quick_page(WebUserPtr up,time_t ct,char *urls,char *urlt);

extern void
LOGR_add_user_entry_page_by_name(WebUserPtr usn,WebStatPtr wsf, char *url);

extern WebUgraphPtr
LOGR_find_ugraph_in_graphs_list(LNode_type *lgraphs, WebUgraphPtr ugn);

extern WebPathPtr
LOGR_find_path_in_list(LNode_type *lpaths, WebPathPtr wpn);

void
LOGR_user_manager(WebStatPtr wsf, char *date, char *urls, char *urlt, 
		  char *dns, char *ua,TypeEdgeReferer ter, GraphFrame *gf)
{
  WebUserPtr up = NULL;
  time_t ct;
  short qpage = 0;
  short cus = LOGR_get_compute_user_sessions(wsf);
  static int first = 0;

  if(!cus)
      return;

  if(!date || !urls || !urlt || !dns || !ua)
      return;

  first++;
  if(first == 1)
      printf("Computing User Sessions\n");

  /* Missing nacc */
  /* printf("Date %s, TER %d, URLS %s URLT %s, DNS %s, UA %s\n", date, ter, 
     urls, urlt, dns,ua);*/
  
  ct = HTParseTimeApache(date);

  LOGR_check_if_user_is_finished(wsf,date);

  if(LOGR_is_user_agent_spider(wsf,ua))
      return;

  if(LOGR_is_object(urlt))
      return;

  if(ter == EXTERNAL_REFERER && LOGR_is_url_non_html(urlt))
      return;
	
  if(LOGR_type_url(urlt) == RDYNAMIC_REF)
      return;

  up = find_user_in_list_current_users(wsf->lcusers,dns);

  qpage = LOGR_is_quick_page(up,ct,urls,urlt);

  if(up)
  {
    LOGR_set_user_end_time(up,ct);

    if(ter == INTERNAL_REFERER)
    {
      WebUgraphPtr ugn= LOGR_get_user_info(up);
      void *GArray = NULL;
      WebGenLinkPtr gln = NULL;
      WebPathPtr cpath = NULL;	    

      if(!ugn)
      {
	ugn = new_web_ugraph_node();
	GArray = init_graph_array();
	LOGR_set_ugraph_info(ugn,GArray);
	LOGR_set_user_info(up,(void *)ugn);
	cpath = LOGR_get_user_current_path(up);
      }
      else
      {
	GArray = LOGR_get_ugraph_info(ugn);
	cpath = LOGR_get_user_current_path(up);
      }
      gln = LOGR_add_edge_graph(GArray,urls, urlt,wsf,gf);
      LOGR_add_path_edge(cpath,gln);
      LOGR_add_user_time(up,(void *)ct); 
      LOGR_inc_user_naccesses(up);
    }
    else if(ter == EXTERNAL_REFERER && qpage == 0)
    {
      WebUserPtr nup = NULL;
      nup = LOGR_new_web_user_info(dns,urls,urlt);
      /*LOGR_add_user_entry_page_by_name(nup,wsf,urlt);*/

      add_user_to_list_current_users((void *)wsf->lcusers,nup);
      
      /*printf("1 Finish User\n");*/
      
      LOGR_terminate_user(wsf,up);
      
      LOGR_set_user_start_time(nup,ct);
      LOGR_set_user_end_time(nup,ct);
      LOGR_add_user_time(nup,(void *)ct);
    }
    else if(ter == EXTERNAL_REFERER && qpage == 1)
    {
	LOGR_add_user_entry_page_by_name(up,wsf,urlt);
    }
  } 
  else /* If user is not found */
  {
    WebUserPtr nup = NULL;	
    nup = LOGR_new_web_user_info(dns,urls,urlt);
    /*LOGR_add_user_entry_page_by_name(nup,wsf,urlt);*/

    add_user_to_list_current_users((void *)wsf->lcusers,nup);
      
    LOGR_set_user_start_time(nup,ct);
    LOGR_set_user_end_time(nup,ct);

    if(ter == INTERNAL_REFERER)
    {
      WebUgraphPtr ugn= NULL;
      void *GArray = NULL;
      WebGenLinkPtr gln = NULL;
      WebPathPtr cpath = NULL;	    
      
      ugn = new_web_ugraph_node();
      GArray = init_graph_array();
      LOGR_set_ugraph_info(ugn,GArray);
      LOGR_set_user_info(nup,(void *)ugn);
      cpath = LOGR_get_user_current_path(nup);
      gln = LOGR_add_edge_graph(GArray,urls, urlt,wsf,gf);
      LOGR_add_path_edge(cpath,gln);
      LOGR_add_user_time(nup,(void *)ct);
    }
    else if(ter == EXTERNAL_REFERER)
    {
	/* Do nothing */
    }	
  }
}

void
LOGR_check_if_user_is_finished(WebStatPtr wsf,char *date)
{
    HTList * cur = wsf ? (HTList *)wsf->lcusers : NULL;
    WebUserPtr pres, tmpu;
    time_t ct = HTParseTimeApache(date);

    if(!wsf)
	return;
/*
	// This implementation is prone to error:
	//	if dt > LOGR_TIME_FRAME, cur will be free'd
	//	and thus th HTList_nextObject will be accessing
	//	data which may or may not be there (or may be
	//	sometime else
    while ((pres = (WebUserPtr) HTList_nextObject(cur))) {
	time_t et = LOGR_get_user_end_time(pres);
	double dt = difftime(ct,et);
	if( dt > LOGR_TIME_FRAME)
	{
	    LOGR_terminate_user(wsf,pres);
	}
    }
*/
	pres = (WebUserPtr)HTList_nextObject(cur);
	while(pres != NULL) {
		time_t et = LOGR_get_user_end_time(pres);
		double dt = difftime(ct,et);
		if(dt > LOGR_TIME_FRAME) {
			tmpu = HTList_nextObject(cur);
			LOGR_terminate_user(wsf,pres);
			pres = tmpu;
		}
		else {
			pres = HTList_nextObject(cur);
		}
	}

    return;
}

void
LOGR_terminate_user(WebStatPtr wsf,WebUserPtr usn)
{
  WebUgraphPtr ugn= NULL;
  WebUgraphPtr ngn= NULL;
  WebPathPtr wpn = NULL;
  WebPathPtr nwpn = NULL;
  static int i = 0;
  
  void *GArray = NULL;

  if(!wsf || !usn)
      return;

  HTList_removeObject((HTList *)wsf->lcusers,usn);

  wpn = LOGR_get_user_current_path(usn);

  if(!wpn)
  {      
      /*printf("Error Path is empty\n");*/
      delete_web_user_node(usn);
      return;
  }

  if(wpn && LOGR_is_path_empty(wpn))
  {
      /*printf("Path is empty\n");*/
      delete_web_user_node(usn);
      return;
  }

  if(i%1000)
      printf("Computing User Session %d\n",i++ );

  /*LOGR_print_user(usn);*/

  Insert_linked_list(wsf->lusers,create_new_node_llist((char *)usn));   

  /* User Graphs */

  ugn= LOGR_get_user_info(usn);
  GArray = LOGR_get_ugraph_info(ugn);

  LOGR_sort_graph_edges(GArray);
  
  ngn = LOGR_find_ugraph_in_graphs_list(wsf->lgraphs, ugn);

  if(!ngn)
  {
      ngn = ugn;
      Insert_linked_list(wsf->lgraphs,create_new_node_llist((char *)ngn));  
  }
  else
  {
      delete_web_ugraph_node(ugn);
      LOGR_inc_ugraph_naccesses(ngn);
  }
  LOGR_add_ugraph_user(ngn,usn);

  /* Paths */

  nwpn = LOGR_find_path_in_list(wsf->lpaths,wpn);
  if(!nwpn)
  {
      nwpn = wpn;
      Insert_linked_list(wsf->lpaths,create_new_node_llist((char *)nwpn));  
  }
  else
  {
      delete_web_path_node(wpn);
      LOGR_set_user_current_path(usn,nwpn);
      LOGR_inc_path_naccesses(nwpn);
  }

  LOGR_add_ugraph_path(ngn,nwpn); /* check if this path is already in graph*/

}
void
LOGR_print_entry_pages(WebUserPtr up)
{
    LNode_type *ptr = NULL;
    LNode_type *lepages = NULL;

    if(!up)
	return;
    lepages = LOGR_get_user_lepages(up);

    if(lepages && is_empty_list(lepages))
	return;

    printf("\tList of Rest Entry Pages\n");
    for(ptr=lepages->back; ptr!=lepages; ptr=ptr->back)
    {
	WebGenPagePtr gpp = (WebGenPagePtr)ptr->info;
	char * url = gpp ? (char *)LOGR_get_gen_url(gpp) : NULL;
	printf("\t%s\n",url ? url : "NULL");
    }
}

void
LOGR_print_user(WebUserPtr up)
{
    char * uname = NULL;
    long nacc = 0;
    char *urls = 0;
    char *urlt = 0;
    WebPathPtr upn = NULL;
    if(!up)
	return;

    uname = LOGR_get_user_name(up);
    nacc = LOGR_get_user_naccesses(up);
    upn = LOGR_get_user_current_path(up);
    urls = LOGR_get_user_referer(up);
    urlt = LOGR_get_user_entry_page(up);
    printf("User\n");
    printf("\tName %s\n", uname ? uname : "NULL");
    printf("\tNacc %ld\n",nacc);
    printf("\tFirst Edge %s - %s\n", urls ? urls : "NULL", urlt ? urlt : "NULL");
    LOGR_print_entry_pages(up);
    LOGR_print_path(upn);
    /* Print times */
    /* Print graph */
}

void
LOGR_print_users_info(LNode_type *lusers)
{
    LNode_type *ptr = NULL;
    if(!lusers)
	return;
    printf("List of Users \n");
    for(ptr = lusers->back ; ptr != lusers ; ptr=ptr->back)
    {	
	WebUserPtr up = (WebUserPtr)ptr->info;
	LOGR_print_user(up);
    }
}

void
LOGR_print_user_graph(WebUgraphPtr ugp)
{
    void *GArray = NULL;
    long nacc = 0;
    int i = 0;
    int sg = 0;
    HTArray *garray = NULL;
    if(!ugp)
	return;
    GArray = LOGR_get_ugraph_info(ugp);
    garray = (HTArray *)GArray;
    sg = HTArray_size(garray);
    nacc = LOGR_get_ugraph_naccesses(ugp);
    printf("Graph \n");
    printf("\t Nacc %ld\n",nacc);
    for (i = 0; i < sg; i++)
    {
      WebGenLinkPtr gln = (WebGenLinkPtr)(HTArray_data(garray)[i]);
      char *urls = (char *)LOGR_get_gen_url_source(gln);
      char *urlt = (char *)LOGR_get_gen_url_target(gln);
      printf("\tEdge %s - %s\n", urls ? urls : "NULL", urlt ? urlt : "NULL");
    }
    /* Print Users */
    /* Print Paths */
}

void
LOGR_print_graphs_info(LNode_type *lgraphs)
{
    LNode_type *ptr = NULL;
    int i = 0;
    if(!lgraphs)
	return;
    printf("List of Graphs \n");
    for(ptr = lgraphs->back ; ptr != lgraphs ; ptr=ptr->back)
    {	
	WebUgraphPtr ugp = (WebUgraphPtr)ptr->info;
	printf("GRAPH %d\n",i++);
	LOGR_print_user_graph(ugp);
    }
}

void
LOGR_print_path(WebPathPtr upn)
{
    LNode_type *ledges = NULL;
    LNode_type *ptr = NULL;
    long nacc = 0;
    if(!upn)
	return;
    nacc = LOGR_get_path_naccesses(upn);
    ledges = LOGR_get_path_ledges(upn);
    printf("Path \n");
    printf("\t Nacc %ld\n",nacc);
    for(ptr=ledges->back; ptr != ledges; ptr=ptr->back)
    {
	WebGenLinkPtr gln = (WebGenLinkPtr)ptr->info;
	char *urls = (char *)LOGR_get_gen_url_source(gln);
	char *urlt = (char *)LOGR_get_gen_url_target(gln);
	printf("\tEdge %s - %s\n", urls ? urls : "NULL", urlt ? urlt : "NULL");
    }
}

void
LOGR_print_paths_info(LNode_type *lpaths) 
{
    LNode_type *ptr = NULL;
    int i = 0;
    if(!lpaths)
	return;
    printf("List of Paths \n");
    for(ptr = lpaths->back ; ptr != lpaths ; ptr=ptr->back)
    {	
	WebPathPtr upn = (WebPathPtr)ptr->info;
	printf("PATH %d\n",i++);
	LOGR_print_path(upn);
    }
}

void
LOGR_print_current_users_info(void *lcusers)
{
    HTList *cur = (HTList *)lcusers;
    WebUserPtr pres;
    if(!lcusers)
	return;

    printf("Current users \n");
    while ((pres = (WebUserPtr) HTList_nextObject(cur))) {
	LOGR_print_user(pres);
    }
 
}
void
LOGR_print_user_sessions_info(WebStatPtr wsf)
{
    LOGR_print_users_info(wsf->lusers);
    LOGR_print_current_users_info(wsf->lcusers);
    LOGR_print_graphs_info(wsf->lgraphs);
    LOGR_print_paths_info(wsf->lpaths);
}


short
LOGR_is_quick_page(WebUserPtr up,time_t ct,char *urls,char *urlt)
{
    time_t lt;
    char *ref = NULL;

    if(!up || !urls || !urlt)
	return 0;

    lt = LOGR_get_user_end_time(up);
    ref = LOGR_get_user_referer(up);

    if(!ref)
	return 0;
    if(strcmp(ref,urls))
	return 0;
    if(abs(difftime(ct,lt)) < 2)
	if(!LOGR_is_url_non_html(urlt))
	    return 1;
    return 0;
}
